package com.example.unisys.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.example.unisys.annotation.Log;
import com.example.unisys.annotation.Limit;
import com.example.unisys.authentication.JWTToken;
import com.example.unisys.cache.RedisService;
import com.example.unisys.cache.UserManager;
import com.example.unisys.common.Response;
import com.example.unisys.common.STATUS;
import com.example.unisys.common.UnisysConstant;
import com.example.unisys.common.property.UnisysProperty;
import com.example.unisys.entity.User;
import com.example.unisys.form.ActiveUserForm;
import com.example.unisys.form.LoginForm;
import com.example.unisys.service.UserService;
import com.example.unisys.utils.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

import java.time.LocalDateTime;
import java.util.Objects;

@Validated
@RestController
@RequestMapping(value = "/apis/v1/auth/", produces = "application/json; charset=utf-8")
public class UserController {

    @Autowired
    private UnisysProperty unisysProperty;

    @Autowired
    UserService userService;
    @Autowired
    UserManager userManager;
    @Autowired
    RedisService redisService;
    @Autowired
    ObjectMapper objectMapper;

    @RequestMapping(value = "login", method = {RequestMethod.POST})
    @Log("登录入口")
    @Limit(key = "login", period = 60, count = 20, name = "登录接口", prefix = "limit")
    public Response login(@RequestBody JSONObject jsonParam,HttpServletRequest request)throws Exception {
        System.out.println(jsonParam.toJSONString());
//        LoginForm userForm = JSONObject.parseObject(jsonParam.toJSONString(), LoginForm.class);
        LoginForm userForm = JSONObject.toJavaObject(jsonParam, LoginForm.class);
//        User curUser = userService.getUserByName(userForm.getUsername());
        //使用cache
        User curUser = userManager.getUser(userForm.getUsername());
        //判断用户是否存在
        if (curUser == null) return Response.builder().status(STATUS.BAD_REQUEST).message("无该用户名用户").build();

        if (!userForm.check(curUser.getPassword())) {
            return Response.builder().status(STATUS.BAD_REQUEST).message("密码错误").build();

        } else {
            if (curUser.getIs_forbidden() != 1) {
                /**
                 * 合法用户
                 * */
                //生成加密token
                String token = EncryptUtil.encryptToken(JWTUtil.sign(curUser.getUsername(), curUser.getPassword()));
                //设置token过期时间
                LocalDateTime expireTime = LocalDateTime.now().plusSeconds(unisysProperty.getShiro().getJwtTimeOut());
                String expireTimeStr = DateUtil.formatFullTime(expireTime);
                JWTToken jwtToken = new JWTToken(token, expireTimeStr);
                //保存到cache
                this.saveTokenToRedis(curUser, jwtToken, request);
                //返回加密token
                return Response.builder().data(jwtToken.getToken()).status(STATUS.SUCCESS).build();
            }
            return Response.builder().status(STATUS.BAD_REQUEST).message("用户已禁用").data("用户已禁用").build();
        }
    }

    @RequestMapping(value = "info", method = {RequestMethod.GET})
    public Response getInfo(@CookieValue("Admin-Token") String token) {
        //需要解密
        JWTToken jwtToken = new JWTToken(EncryptUtil.decryptToken(token));
        String username = Objects.requireNonNull(JWTUtil.getUsername(jwtToken.getToken()));
        String password = userService.getPassWord(username).trim();
        if (JWTUtil.verify(jwtToken.getToken(), username, password)) {
            User user=userManager.getUser(username);
            return Response.builder().status(STATUS.SUCCESS).data(user).build();
        }
        return Response.builder().status(STATUS.BAD_REQUEST).data("登录已过期").message("登录已过期").build();
    }


    @RequestMapping(value = "logout", method = {RequestMethod.POST})
    public Response logout(@CookieValue("Admin-Token") String token, HttpServletRequest request) {
        JWTToken jwtToken = new JWTToken(EncryptUtil.decryptToken(token));
        String username = Objects.requireNonNull(JWTUtil.getUsername(jwtToken.getToken())).trim();
        User curUser = userManager.getUser(username);
        String ip = IpUtil.getIpAddr(request);
        curUser.setIp(ip);
        curUser.setPrev_time(DateUtil.getCurrentTime());
        userService.update(curUser);
        return Response.builder().status(STATUS.SUCCESS).build();
    }

    /**
     * 保存token到cache,同时更新当前用户时间和ip
     * @param user
     * @param token
     * @param request
     * @return
     * @throws Exception
     */
    private void saveTokenToRedis(User user, JWTToken token, HttpServletRequest request) throws Exception {
        String ip = IpUtil.getIpAddr(request);

        // 构建在线用户
        ActiveUserForm activeUser = new ActiveUserForm();
        activeUser.setUsername(user.getUsername());
        activeUser.setIp(ip);
        activeUser.setToken(token.getToken());
        activeUser.setLoginAddress(AddressUtil.getCityInfo(ip));
        // zset 存储登录用户，score 为过期时间戳
        this.redisService.zadd(UnisysConstant.ACTIVE_USERS_ZSET_PREFIX, Double.valueOf(token.getExipreAt()), objectMapper.writeValueAsString(activeUser));
        // redis 中存储这个加密 token，key = 前缀 + 加密 token + .ip
        this.redisService.set(UnisysConstant.TOKEN_CACHE_PREFIX + token.getToken() + StringPool.DOT + ip, token.getToken(), unisysProperty.getShiro().getJwtTimeOut() * 1000);
    }
}
